pub fn use_trait(){
    use_person();
    use_trait_as_arg();
    use_trait_as_return();
}

trait Descriptive {
    fn describe(&self) -> String{
        String::from("[Object]")
    }
}

struct Person {
    name: String,
    age: u8
}

impl Person {
    fn to_string(&self) -> String {
        format!("{}-{}", self.name, self.age)
    }
}
impl Descriptive for Person {
}

fn use_person(){
    let p = Person { name: String::from("Hi"), age : 18 };
    println!("use default describe impl of person:{}", p.describe());
    println!("to_string of person:{}", p.to_string());
}

fn use_trait_as_arg(){
    fn output(object : & impl Descriptive){ //method 1
        println!("{}", object.describe());
    }
    let p = Person { name: String::from("Hi"), age : 18 };
    output(&p);

    fn output_2<T: Descriptive>(object : &T){ // generic style of use impl trait as argument
        println!("{}", object.describe());
    }
    output_2(&p);

    // multi-trait; some syntax for use impl multi-trait
    // fn function(item: impl Summary + Display) -> i32 {}
    // fn function<T: Summary + Display>(item: T)->i32 {}
    // fn function<T>(item T) -> i32  where T: Summary + Display {}
}


fn use_trait_as_return(){
    fn person() -> impl Descriptive {
        Person {
            name: String::from("Hi"),
            age: 10
        }
    }
    println!("{}", person().describe());
}



/*
struct A<T> {}
impl<T:  Display + Summary> A<T> {
    fn d(&self){}
}
    let a = A<String>{}; // ==>  String must impl Display + Summary
*/

